package br.edu.ufcg.unknown;

import java.io.File;
import java.util.LinkedList;

import br.edu.ufcg.unknown.exception.AnalisadorLexicoUnknownRuntimeException;
import br.edu.ufcg.unknown.exception.UnknownException;
import br.edu.ufcg.unknown.lexico.AnalisadorLexico;
import br.edu.ufcg.unknown.lexico.Token;

public class MainAnalisadorLexico {

	public static String LINE_SEPARATOR = System.getProperty("line.separator");

	public static void main(String[] args) {

		if (args.length != 1) {
			System.err.println("Erro! Use: java " + MainAnalisadorLexico.class.getName() + " <arquivo do código-fonte>");
			System.out.println("Exemplo: java " + MainAnalisadorLexico.class.getName() + " exemplos/file1.unknown");
			System.exit(1);
		}

		File file = new File(args[0]);

		if (!file.exists()) {
			System.err.println("Erro! Arquivo não existe: " + file.getName());
			System.exit(1);
		}

		Token token = null;
		LinkedList<Token> tokens = new LinkedList<Token>();
		AnalisadorLexico al = null;

		try {
			al = new AnalisadorLexico(file);
			while ((token = al.getProxToken()) != null) {
				tokens.add(token);
			}

			printTokens(tokens);

		} catch (AnalisadorLexicoUnknownRuntimeException e) {
			System.err.println("Erro! " + e.getMessage() + ": <" + (e.getCaractere() != null ? e.getCaractere() : e.getToken().getLexema())
					+ "> Linha: " + e.getLinha() + " Coluna: " + e.getColuna());
		} catch (UnknownException e) {
			e.printStackTrace();
		}

	}

	private static void printTokens(LinkedList<Token> tokens) {
		int tamMaxLexema = "<LEXEMA>".length();
		int tamMaxTipo = "<TIPO>".length();
		int tamMaxLinha = "<LINHA>".length();
		int tamMaxColuna = "<COLUNA>".length();

		char caractereHorizontal = '=';
		char caractereVertical = '|';

		StringBuilder sb = null;
		String lexema = null;

		for (Token token : tokens) {
			lexema = filtrarQuebraDeLinha(token.getLexema());
			tamMaxLexema = Math.max(tamMaxLexema, lexema.length());
			tamMaxTipo = Math.max(tamMaxTipo, token.getTipo().length());
			tamMaxLinha = Math.max(tamMaxLinha, String.valueOf(token.getLinha()).length());
			tamMaxColuna = Math.max(tamMaxColuna, String.valueOf(token.getColuna()).length());
		}

		tamMaxLexema += 2;
		tamMaxTipo += 2;
		tamMaxLinha += 2;
		tamMaxColuna += 2;

		sb = new StringBuilder();

		appendCaractere(sb, caractereHorizontal, tamMaxLexema + tamMaxTipo + tamMaxLinha + tamMaxColuna + 5);
		sb.append(LINE_SEPARATOR);

		sb.append(caractereVertical);
		appendEspacoEmBranco(sb, (tamMaxLexema - "<LEXEMA>".length()) / 2);
		sb.append("<LEXEMA>");
		appendEspacoEmBranco(sb, (tamMaxLexema - "<LEXEMA>".length()) - (tamMaxLexema - "<LEXEMA>".length()) / 2);
		sb.append(caractereVertical);
		appendEspacoEmBranco(sb, (tamMaxTipo - "<TIPO>".length()) / 2);
		sb.append("<TIPO>");
		appendEspacoEmBranco(sb, (tamMaxTipo - "<TIPO>".length()) - (tamMaxTipo - "<TIPO>".length()) / 2);
		sb.append(caractereVertical);
		appendEspacoEmBranco(sb, (tamMaxLinha - "<LINHA>".length()) / 2);
		sb.append("<LINHA>");
		appendEspacoEmBranco(sb, (tamMaxLinha - "<LINHA>".length()) - (tamMaxLinha - "<LINHA>".length()) / 2);
		sb.append(caractereVertical);
		appendEspacoEmBranco(sb, (tamMaxColuna - "<COLUNA>".length()) / 2);
		sb.append("<COLUNA>");
		appendEspacoEmBranco(sb, (tamMaxColuna - "<COLUNA>".length()) - (tamMaxColuna - "<COLUNA>".length()) / 2);
		sb.append(caractereVertical);
		sb.append(LINE_SEPARATOR);

		appendCaractere(sb, caractereHorizontal, tamMaxLexema + tamMaxTipo + tamMaxLinha + tamMaxColuna + 5);
		sb.append(LINE_SEPARATOR);

		for (Token token : tokens) {
			lexema = filtrarQuebraDeLinha(token.getLexema());

			sb.append(caractereVertical);
			appendEspacoEmBranco(sb, (tamMaxLexema - lexema.length()) / 2);
			sb.append(lexema);
			appendEspacoEmBranco(sb, (tamMaxLexema - lexema.length()) - (tamMaxLexema - lexema.length()) / 2);

			sb.append(caractereVertical);
			appendEspacoEmBranco(sb, (tamMaxTipo - token.getTipo().length()) / 2);
			sb.append(token.getTipo());
			appendEspacoEmBranco(sb, (tamMaxTipo - token.getTipo().length()) - (tamMaxTipo - token.getTipo().length()) / 2);

			sb.append(caractereVertical);
			appendEspacoEmBranco(sb, (tamMaxLinha - String.valueOf(token.getLinha()).length()) / 2);
			sb.append(token.getLinha());
			appendEspacoEmBranco(sb, (tamMaxLinha - String.valueOf(token.getLinha()).length())
					- (tamMaxLinha - String.valueOf(token.getLinha()).length()) / 2);

			sb.append(caractereVertical);
			appendEspacoEmBranco(sb, (tamMaxColuna - String.valueOf(token.getColuna()).length()) / 2);
			sb.append(token.getColuna());
			appendEspacoEmBranco(sb, (tamMaxColuna - String.valueOf(token.getColuna()).length())
					- (tamMaxColuna - String.valueOf(token.getColuna()).length()) / 2);

			sb.append(caractereVertical);
			sb.append(LINE_SEPARATOR);
		}

		appendCaractere(sb, caractereHorizontal, tamMaxLexema + tamMaxTipo + tamMaxLinha + tamMaxColuna + 5);
		sb.append(LINE_SEPARATOR);

		System.out.println("OBS: Quebra-de-Linha aparece como '\\n'");
		System.out.println(sb.toString());

	}

	private static String filtrarQuebraDeLinha(String lexema) {
		StringBuilder sb = new StringBuilder();

		for (int i = 0; i < lexema.length(); i++) {
			if (lexema.charAt(i) == '\n') {
				sb.append("\\n");
			} else {
				sb.append(lexema.charAt(i));
			}
		}

		return sb.toString();
	}

	private static void appendEspacoEmBranco(StringBuilder sb, int quant) {
		appendCaractere(sb, ' ', quant);
	}

	private static void appendCaractere(StringBuilder sb, char caractere, int quant) {
		for (int i = 0; i < quant; i++) {
			sb.append(caractere);
		}
	}

}
